#include "guidemapwindow.h"
#include <osgWidget\WindowManager>
#include "resourceloader.h"
#include <osgGA\CameraManipulator>
#include <osgViewer\View>
#include "datatypedefine.h"
#include "utility.h"
#include "osgtooltip.h"

#define WINDOW_WIDTH			0.97
#define WINDOW_HEIGHT			WINDOW_WIDTH
#define GUIDE_LABEL_SIZE		20

namespace Gui2D
{
	GuideMapWindow::GuideMapWindow(osgWidget::WindowManager* wm):_mainView(NULL),_windowManager(wm)
		,_backgroundImage(""),_type(0),_mainCanvas(NULL)
	{
		std::string s;
		_overEventHandler = new Type_1Func<void,GuideMapWindow,std::string>(&GuideMapWindow::overEvent,this,s);
		_leaveEventHandler = new Type_1Func<void,GuideMapWindow,std::string>(&GuideMapWindow::leaveEvent,this,s);
	}

	void GuideMapWindow::setBackgroundImage(const QString& image)
	{
		_backgroundImage = image;
		if(_backgroundL.valid())
		{
			_backgroundL->setTexture(CoreBase::ResourceLoader::GetInstance().getTextureByFileName(_backgroundImage));
		}
	}

	QString GuideMapWindow::getBackgroundImage()
	{
		return _backgroundImage;
	}

	void GuideMapWindow::setMainView(osgViewer::View* mv)
	{
		_mainView = mv;
	}

	void GuideMapWindow::setWindowManager(osgWidget::WindowManager* wm)
	{
		if(_windowManager == NULL)
		{
			_windowManager = wm;
		}
	}

	GuideMapWindow::~GuideMapWindow()
	{}

	void GuideMapWindow::initWindow()
	{
		if(!_mainCanvas.valid())
		{
			float windowwidth = _windowManager->getWidth()*WINDOW_WIDTH;
			float windowheight = _windowManager->getHeight()*WINDOW_HEIGHT;
			_mainCanvas = new osgWidget::Canvas("_mainCanvas");
			_mainCanvas->resize(windowwidth,windowheight);
			_mainCanvas->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.0f);
			//_mainCanvas->setNodeMask(~MASK_2D);
			_mainCanvas->setPosition((windowwidth - windowwidth*WINDOW_WIDTH)*0.5f,windowheight*(1-WINDOW_HEIGHT)*0.5f,0);
			osg::ref_ptr<osg::Image> imagepath = CoreBase::ResourceLoader::GetInstance().getImageByFileName(_backgroundImage);
			/*osg::ref_ptr<osg::Image> borderimage = CoreBase::ResourceLoader::GetInstance().getImageByFileName("\\scenetextures\\guidemap\\border.png");
			osg::ref_ptr<osg::Image> topimage = CoreBase::ResourceLoader::GetInstance().getImageByFileName("\\scenetextures\\guidemap\\top.png");
			osg::ref_ptr<osg::Image> topcenterimage = CoreBase::ResourceLoader::GetInstance().getImageByFileName("\\scenetextures\\guidemap\\topcenter.png");*/
			_backgroundL = new osgWidget::Label("background label", "");
			_backgroundL->setColor(osgWidget::Color(1,1,1,1));
			_backgroundL->setCanFill(true);
			_backgroundL->setWidth(windowwidth);
			_backgroundL->setEventMask(osgWidget::EVENT_NONE);
			_backgroundL->setHeight(windowheight);
			_backgroundL->setImage(imagepath,true);
			/*_backgroundW = new osgWidget::Box("background", osgWidget::Box::HORIZONTAL);
			_backgroundW->getBackground()->setColor(1.0f,1.0f,1.0f,0.0f);
			_backgroundW->getBackground()->setImage(imagepath,true);
			_backgroundW->addWidget(_backgroundL);
			_backgroundW->setEventMask(osgWidget::EVENT_ALL);
			_backgroundW->resize(embedww,embedwh);*/
			//_mainCanvas->getEmbeddedWindow()->setWindow(_backgroundW);
			//_mainCanvas->setVisibilityMode(osgWidget::Window::VM_ENTIRE);
			_mainCanvas->addWidget(_backgroundL,0,0);
			_mainCanvas->addCallback(new osgWidget::Callback(&GuideMapWindow::moveWindow,this, osgWidget::EVENT_MOUSE_DRAG));
			initGuideLabel();
			createSmallMap();
		}
	}

	void GuideMapWindow::showSmallMap()
	{
		if(_type == 1)
			return;
		initWindow();
		_windowManager->removeChild(_mainCanvas);
		_windowManager->removeChild(_transformNode);
		_windowManager->addChild(_hudCamera);
		_type = 1;
		for(QMap<QString,RemarkStruct>::Iterator iter = _remarkMap.begin();iter!=_remarkMap.end();++iter)
		{
			_mainCanvas->removeWidget(iter.value()._label);
		}
	}
	
	void GuideMapWindow::showBigMap()
	{
		if(_type == 2)
			return;
		initWindow();
		_windowManager->addChild(_mainCanvas);
		_windowManager->addChild(_transformNode);
		_windowManager->removeChild(_hudCamera);
		_type = 2;
		float windowheight = _windowManager->getHeight();
		float windowwidth = _windowManager->getWidth();
		for(QMap<QString,RemarkStruct>::Iterator iter = _remarkMap.begin();iter!=_remarkMap.end();++iter)
		{
			//update remark label
			float normalizex = 1.0f,normalizey = 1.0f;
			normalizex = (iter.value()._pos.x() - _coordinateMinXY.x())/(_coordinateMaxXY.x() - _coordinateMinXY.x());
			normalizey = (iter.value()._pos.y() - _coordinateMinXY.y())/(_coordinateMaxXY.y() - _coordinateMinXY.y());
			//iter.value()._osgButtonBase->setPosition();
			_mainCanvas->addWidget(iter.value()._label,windowwidth*WINDOW_WIDTH*normalizex,windowheight*WINDOW_HEIGHT*normalizey);
		}
	}

	bool GuideMapWindow::moveWindow(osgWidget::Event& ev)
	{
		_mainCanvas->setPosition(_mainCanvas->getPosition() + osgWidget::Point(ev.x,ev.y,0));
		_mainCanvas->update();
		return true;
	}

	bool GuideMapWindow::isSmallMap()
	{
		return _type == 1;
	}

	void GuideMapWindow::hide()
	{
		_windowManager->removeChild(_mainCanvas);
		_windowManager->removeChild(_transformNode);
		_windowManager->removeChild(_hudCamera);
		for(QMap<QString,RemarkStruct>::Iterator iter = _remarkMap.begin();iter!=_remarkMap.end();++iter)
		{
			_mainCanvas->removeWidget(iter.value()._label);
		}
	}

	void GuideMapWindow::update()
	{
		if(_mainView!=NULL)
		{
			osg::Matrix cameramatrix = _mainView->getCameraManipulator()->getInverseMatrix();
			osg::Vec3 eye, center, up ;
			cameramatrix.getLookAt( eye, center, up ) ;
			osg::Vec3 pos = cameramatrix.inverse(cameramatrix).getTrans();
			float normalizex = 1.0f,normalizey = 1.0f;
			float windowheight = _windowManager->getHeight();
			float windowwidth = _windowManager->getWidth();
			osg::Vec3 direction = center - eye;
			direction._v[2] = 0.0;
			direction.normalize();
			float angle = acos(direction.x())*180.0/3.1415926;
			angle = direction.y()<0?360-angle:angle;
			if(_type == 2)
			{
				normalizex = (pos.x() - _coordinateMinXY.x())/(_coordinateMaxXY.x() - _coordinateMinXY.x());
				normalizey = (pos.y() - _coordinateMinXY.y())/(_coordinateMaxXY.y() - _coordinateMinXY.y());
				float xoffset = _mainCanvas->getPosition().x();
				float yoffset = _mainCanvas->getPosition().y();
				setGuideLabelTransform(osg::Vec3(xoffset+windowwidth*WINDOW_WIDTH*normalizex,yoffset+windowheight*WINDOW_HEIGHT*normalizey,0),angle);
			}
			else if(_type == 1)
			{
				normalizex = (pos.x() - _coordinateMinXY.x())/(_coordinateMaxXY.x() - _coordinateMinXY.x());
				normalizey = (pos.y() - _coordinateMinXY.y())/(_coordinateMaxXY.y() - _coordinateMinXY.y());
				float size = windowheight*SMALL_MAP_SIZE;
				setGuideLabelTransform(osg::Vec3(size/2.0f,size/2.0f,0),angle);
				osg::Matrix transformmatrix = osg::Matrix::translate(osg::Vec3(size/2.0f - windowwidth*WINDOW_WIDTH*normalizex,
					size/2.0f - windowheight*WINDOW_HEIGHT*normalizey,0));
				_smallMapTransformNode->setMatrix( transformmatrix );
			}
		}
	}

	void GuideMapWindow::setCoordinateMinXY(osg::Vec2f xy)
	{
		_coordinateMinXY = xy;
	}

	osg::Vec2f GuideMapWindow::getCoordinateMinXY()
	{
		return _coordinateMinXY;
	}

	void GuideMapWindow::setCoordinateMaxXY(osg::Vec2f xy)
	{
		_coordinateMaxXY = xy;
	}

	osg::Vec2f GuideMapWindow::getCoordinateMaxXY()
	{
		return _coordinateMaxXY;
	}

	void GuideMapWindow::initGuideLabel()
	{
		_transformNode = new osg::MatrixTransform;
		_gNode = new osg::Geode;
		_geo     = new osg::Geometry;
		_vArray = new osg::Vec3Array;
		_cArray = new osg::Vec4Array;
		_cArray->push_back(osg::Vec4(1,1,1,1));
		_tArray = new osg::Vec2Array;
		_gNode->setUpdateCallback(new LabelUpdateCallback(this));

		osg::StateSet* ss = _gNode->getOrCreateStateSet() ;
		ss->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF|osg::StateAttribute::PROTECTED);
		ss->setMode(GL_LIGHTING,osg::StateAttribute::OFF|osg::StateAttribute::PROTECTED);
		ss->setMode(GL_CULL_FACE, osg::StateAttribute::OFF|osg::StateAttribute::PROTECTED ) ;
		ss->setRenderBinDetails(RENDER_BACK_NUM,"RenderBin");
		_geo->setVertexArray( _vArray );
		_geo->setColorArray( _cArray );
		_geo->setColorBinding( osg::Geometry::BIND_PER_PRIMITIVE_SET);
		_geo->setTexCoordArray(0, _tArray );
		_gNode->addDrawable( _geo );
		_transformNode->addChild( _gNode );
		clear();
		osg::Vec3 corner =_guidepos + osg::Vec3( -GUIDE_LABEL_SIZE/2.0, -GUIDE_LABEL_SIZE/2.0, 0.0 );
		_vArray->push_back( corner ) ;
		_vArray->push_back( corner + osg::Vec3(0.0, GUIDE_LABEL_SIZE, 0.0 )) ;
		_vArray->push_back( corner + osg::Vec3( GUIDE_LABEL_SIZE, GUIDE_LABEL_SIZE, 0.0 )) ;
		_vArray->push_back( corner + osg::Vec3( GUIDE_LABEL_SIZE, 0.0, 0.0 )) ;

		_tArray->push_back( osg::Vec2(0.0,0.0)) ;
		_tArray->push_back( osg::Vec2(0.0,1.0)) ;
		_tArray->push_back( osg::Vec2(1.0,1.0)) ;
		_tArray->push_back( osg::Vec2(1.0,0.0)) ;

		_geo->setVertexArray( _vArray ) ;
		_geo->setTexCoordArray(0, _tArray ) ;
		_geo->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, _vArray->size())  );

		osg::ref_ptr<osg::Texture2D> arrowtexture = CoreBase::ResourceLoader::GetInstance().getTextureByFileName("\\scenetextures\\guidemap\\arrow.png");
		if(arrowtexture.valid())
		{
			arrowtexture->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR)  ;
			arrowtexture->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR) ;
			ss->setTextureAttributeAndModes ( 0, arrowtexture, osg::StateAttribute::ON|osg::StateAttribute::PROTECTED);
		}
	}

	void GuideMapWindow::setGuideLabelTransform(const osg::Vec3& pos,float rota)
	{
		_guidepos = pos;
		_guideRota = rota;
		osg::Matrix rotmatrix = osg::Matrix::rotate( osg::Quat(osg::DegreesToRadians(rota),osg::Vec3(0.0,0.0,1.0)) ) ;
		rotmatrix = rotmatrix*osg::Matrix::translate( _guidepos ) ;
		_transformNode->setMatrix( rotmatrix ) ;
	}

	void GuideMapWindow::clear()
	{
		_vArray->clear() ;
		_tArray->clear() ;
		int primnums = _geo->getNumPrimitiveSets();
		_geo->removePrimitiveSet( 0, primnums );
	}

	void GuideMapWindow::viewResize(float w,float h)
	{
		if(!_mainCanvas.valid())
			return;
		float windowwidth = _windowManager->getWidth();
		float windowheight = _windowManager->getHeight();
		_backgroundL->setWidth(windowwidth*WINDOW_WIDTH);
		_backgroundL->setHeight(windowheight*WINDOW_HEIGHT);
		float size = windowheight*SMALL_MAP_SIZE;
		_hudCamera->setProjectionMatrix(osg::Matrix::ortho2D(0,size,0,size));
		_hudCamera->setViewport(windowwidth - size,windowheight - size,size,size);

		osg::Vec3 corner(0,0,0);
		osg::Vec3 heightvec(0,size,0);
		osg::Vec3 widthvec(size,0,0);
		osg::Vec3Array* coords = dynamic_cast<osg::Vec3Array*>(_mapGeometry->getVertexArray());
		osg::Vec3 mapheightvec(0,windowheight*WINDOW_HEIGHT,0);
		osg::Vec3 mapwidthvec(windowwidth*WINDOW_WIDTH,0,0);
		(*coords)[0] = corner+mapheightvec;
		(*coords)[1] = corner;
		(*coords)[2] = corner+mapwidthvec;
		(*coords)[3] = corner+mapwidthvec+mapheightvec;
		_mapGeometry->setVertexArray(coords);

		for(QMap<QString,RemarkStruct>::Iterator iter = _remarkMap.begin();iter!=_remarkMap.end();++iter)
		{
			//update remark label
			float normalizex = 1.0f,normalizey = 1.0f;
			normalizex = (iter.value()._pos.x() - _coordinateMinXY.x())/(_coordinateMaxXY.x() - _coordinateMinXY.x());
			normalizey = (iter.value()._pos.y() - _coordinateMinXY.y())/(_coordinateMaxXY.y() - _coordinateMinXY.y());
			iter.value()._osgButtonBase->setPosition(windowwidth*WINDOW_WIDTH*normalizex,windowheight*WINDOW_HEIGHT*normalizey);
		}
		_mainCanvas->resize(windowwidth*WINDOW_WIDTH,windowheight*WINDOW_HEIGHT);
	}

	void GuideMapWindow::createSmallMap()
	{
		float windowwidth = _windowManager->getWidth();
		float windowheight = _windowManager->getHeight();
		float size = windowheight*SMALL_MAP_SIZE;
		_hudCamera = new osg::Camera;
		_hudCamera->setProjectionMatrix(osg::Matrix::ortho2D(0,size,0,size));
		_hudCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
		_hudCamera->setViewMatrix(osg::Matrix::identity());
		_hudCamera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
		_hudCamera->setClearColor( osg::Vec4(0.1725f,0.2706f,0.4157f,1.0));
		_hudCamera->setRenderOrder(osg::Camera::POST_RENDER);
		_hudCamera->setAllowEventFocus(false);
		_hudCamera->setViewport(windowwidth - size,windowheight - size,size,size);

		//osg::ref_ptr<osg::Geode> backgroudgeode = new osg::Geode();
		//_backgroundGeometry = osg::createTexturedQuadGeometry
		//	(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(size,0.0f,0.0f), osg::Vec3(0.0f,size,0.0f));
		//backgroudgeode->addDrawable( _backgroundGeometry );
		//osg::ref_ptr<osg::StateSet> geometrystate2 = _backgroundGeometry->getOrCreateStateSet();
		//geometrystate2->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
		//geometrystate2->setMode(GL_BLEND,osg::StateAttribute::ON);
		////geometrystate2->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
		//osg::ref_ptr<osg::Texture2D> backgroundtexture = CoreBase::ResourceLoader::GetInstance().getTextureByFileName(
		//	"\\scenetextures\\guidemap\\background2.png");
		//if(backgroundtexture != NULL)
		//{
		//	geometrystate2->setTextureAttributeAndModes (0,backgroundtexture,osg::StateAttribute::ON);
		//	geometrystate2->setRenderBinDetails(RENDER_BACK_NUM+1,"RenderBin");
		//}
		//_hudCamera->addChild(backgroudgeode.get());
		
		osg::ref_ptr<osg::Geode> mapgeode = new osg::Geode();
		_mapGeometry = osg::createTexturedQuadGeometry
			(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(windowwidth*WINDOW_WIDTH,0.0f,0.0f), osg::Vec3(0.0f,windowheight*WINDOW_HEIGHT,0.0f));
		mapgeode->addDrawable( _mapGeometry );
		osg::ref_ptr<osg::StateSet> smallmapgeometrystate = _mapGeometry->getOrCreateStateSet();
		smallmapgeometrystate->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
		smallmapgeometrystate->setMode(GL_BLEND,osg::StateAttribute::ON);
		//smallmapgeometrystate->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
		osg::ref_ptr<osg::Texture2D> maptexture = CoreBase::ResourceLoader::GetInstance().getTextureByFileName(_backgroundImage);
		if(maptexture != NULL)
		{
			smallmapgeometrystate->setTextureAttributeAndModes (0,maptexture,osg::StateAttribute::ON);
			smallmapgeometrystate->setRenderBinDetails(RENDER_BACK_NUM-1,"RenderBin");
		}
		_smallMapTransformNode = new osg::MatrixTransform;
		_smallMapTransformNode->addChild( mapgeode );
		_hudCamera->addChild(_smallMapTransformNode);
		_hudCamera->addChild(_transformNode);
	}

	void GuideMapWindow::addRemarkLabel(const QString& id,const QString& texturestring,const QString& withtext,const osg::Vec3& pos)
	{
		if(!_remarkMap.contains(id))
		{
			osg::ref_ptr<OsgButtonBase>	 ob = new OsgButtonBase;
			ob->createButtonLabel(ChineseTexttoStdstring(id),texturestring,"",30,30);
			ob->RegisterEventEffect(osgWidget::EVENT_MOUSE_PUSH,Gui2D::CHANGE_SIZE);
			ob->RegisterEventEffect(osgWidget::EVENT_MOUSE_RELEASE,Gui2D::DEFAULT_SIZE);
			RemarkStruct newstruct;
			newstruct._pos = pos;
			newstruct._osgButtonBase = ob;
			newstruct._label = ob->getButtonBoxLabel();
			newstruct._label->setWidth(30);
			newstruct._label->setHeight(30);
			newstruct._tooltipText = withtext;
			_remarkMap.insert(id,newstruct);
			ob->addFunctionOver(_overEventHandler);
			ob->addFunctionLeave(_leaveEventHandler);
			if(_type == 2)
			{
				float windowheight = _windowManager->getHeight();
				float windowwidth = _windowManager->getWidth();
				float normalizex = 1.0f,normalizey = 1.0f;
				normalizex = (pos.x() - _coordinateMinXY.x())/(_coordinateMaxXY.x() - _coordinateMinXY.x());
				normalizey = (pos.y() - _coordinateMinXY.y())/(_coordinateMaxXY.y() - _coordinateMinXY.y());
				_mainCanvas->addWidget(newstruct._label,windowwidth*WINDOW_WIDTH*normalizex,windowheight*WINDOW_HEIGHT*normalizey);
			}
		}
	}

	void GuideMapWindow::removeRemarkLabel(const QString& id)
	{
		for(QMap<QString,RemarkStruct>::Iterator iter = _remarkMap.begin();iter!=_remarkMap.end();++iter)
		{
			if(iter.value()._label->getName() == ChineseTexttoStdstring(id))
			{
				if(_type == 2)
					_mainCanvas->removeWidget(iter.value()._label);
				_remarkMap.erase(iter);
				break;
			}
		}
	}

	void GuideMapWindow::overEvent(std::string id)
	{
		QString qid = QObject::tr(id.c_str());
		if(_remarkMap.contains(qid))
		{
			osgWidget::Point p = _remarkMap[qid]._label->getPosition() + osg::Vec3(_mainCanvas->getPosition().x(),_mainCanvas->getPosition().y(),0);
			OsgToolTip::GetInstance().setToolTipText(_remarkMap[qid]._tooltipText,p.x(),p.y());
		}
	}

	void GuideMapWindow::leaveEvent(std::string id)
	{
		OsgToolTip::GetInstance().setToolTipText("");
	}
}